home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / fortify.lha / fortify.c next >
Encoding:
C/C++ Source or Header  |  1995-02-03  |  21.8 KB  |  918 lines

  1. /*
  2.  * FILE:
  3.  *   fortify.c
  4.  *
  5.  * DESCRIPTION:
  6.  *     A fortified shell for malloc, realloc, calloc and free.
  7.  *     To use Fortify, each source file will need to #include "fortify.h".  To
  8.  * enable  Fortify,  define the symbol FORTIFY.  If FORTIFY is not defined, it
  9.  * will compile away to nothing.  If you do not have stdout available, you may
  10.  * wish  to  set  an  alternate output function.  See Fortify_SetOutputFunc(),
  11.  * below.
  12.  *     You will also need to link in fortify.o
  13.  *
  14.  *     None of the functions in this file should really be called
  15.  *   directly; they really should be called through the macros
  16.  *   defined in fortify.h
  17.  *
  18.  */
  19. #ifdef FORTIFY
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <math.h>
  25. #include <ctype.h>
  26.  
  27. #define __FORTIFY_C__ /* So fortify.h knows to not define the fortify macros */
  28. #include "fortify.h"
  29.  
  30. #include "ufortify.h" /* the user's options */
  31.  
  32. struct Header
  33. {
  34.     char          *File;   /* The sourcefile of the caller   */
  35.     unsigned long  Line;   /* The sourceline of the caller   */
  36.     size_t         Size;   /* The size of the malloc'd block */
  37.     struct Header *Prev,   /* List pointers                  */
  38.                   *Next; 
  39.     int            Scope;
  40.     int            Checksum;  /* For validating the Header structure; see ChecksumHeader() */
  41. };
  42.  
  43. static int CheckBlock(struct Header *h, char *file, unsigned long line);
  44. static int CheckFortification(unsigned char *ptr, unsigned char value, size_t size);
  45. static void SetFortification(unsigned char *ptr, unsigned char value, size_t size);
  46. static void OutputFortification(unsigned char *ptr, unsigned char value, size_t size);
  47. static int IsHeaderValid(struct Header *h);
  48. static void MakeHeaderValid(struct Header *h);
  49. static int ChecksumHeader(struct Header *h);
  50. static int IsOnList(struct Header *h);
  51. static void OutputHeader(struct Header *h);
  52. static void OutputMemory(struct Header *h);
  53.  
  54. static void st_DefaultOutput(char *String)
  55. {
  56.     printf(String);
  57. }
  58.  
  59. static struct Header *st_Head = 0; /* Head of alloc'd memory list */
  60. static OutputFuncPtr  st_Output = st_DefaultOutput; /* Output function for errors */
  61. static char st_Buffer[256];       /* Temporary buffer for sprintf's */
  62. static int st_Disabled = 0;       /* If true, Fortify is inactive */
  63. static int st_MallocFailRate = 0; /* % of the time to fail mallocs */
  64.  
  65. static char          *st_LastVerifiedFile = "unknown";
  66. static unsigned long  st_LastVerifiedLine = 0;
  67. static int            st_Scope            = 0;
  68. static void           OutputLastVerifiedPoint(void);
  69.  
  70. /*
  71.  * Fortify_malloc() - Allocates a block of memory, with extra bits for
  72.  *                    misuse protection/detection. 
  73.  *
  74.  *    Features:
  75.  *     +  Adds the malloc'd memory onto Fortify's own private list.
  76.  *        (With a checksum'd header to detect corruption of the memory list)
  77.  *     +  Places sentinals on either side of the user's memory with
  78.  *        known data in them, to detect use outside of the bounds
  79.  *        of the block
  80.  *     +  Initializes the malloc'd memory to some "nasty" value, so code
  81.  *        can't rely on it's contents.
  82.  *     +  Can check all sentinals on every malloc.
  83.  *     +  Can generate a warning message on a malloc fail.
  84.  *     +  Can randomly "fail" at a set fail rate
  85.  */
  86. void *FORTIFY_STORAGE
  87. Fortify_malloc(size_t size, char *file, unsigned long line)
  88. {
  89.     unsigned char *ptr;
  90.     struct Header *h;
  91.  
  92.     FORTIFY_LOCK();
  93.  
  94.     if(st_Disabled)
  95.     {
  96.         ptr = malloc(size);
  97.         FORTIFY_UNLOCK();
  98.         return(ptr);
  99.     }
  100.  
  101. #ifdef CHECK_ALL_MEMORY_ON_MALLOC
  102.     Fortify_CheckAllMemory(file, line);
  103. #endif  
  104.  
  105.     if(size == 0)
  106.     {
  107. #ifdef WARN_ON_ZERO_MALLOC
  108.         sprintf(st_Buffer, 
  109.                 "\nFortify: %s.%ld\n         malloc(0) attempted failed\n",
  110.                 file, line);
  111.         st_Output(st_Buffer);
  112. #endif
  113.  
  114.         FORTIFY_UNLOCK();
  115.         return(0);       
  116.     }
  117.  
  118.     if(st_MallocFailRate > 0)
  119.     {
  120.         if(rand() % 100 < st_MallocFailRate)
  121.         {
  122. #ifdef WARN_ON_FALSE_FAIL
  123.             sprintf(st_Buffer, 
  124.                     "\nFortify: %s.%ld\n         malloc(%ld) \"false\" failed\n",
  125.                             file, line, (unsigned long)size);
  126.             st_Output(st_Buffer);
  127. #endif
  128.             FORTIFY_UNLOCK();
  129.             return(0);
  130.         }
  131.     }
  132.   
  133.     /*
  134.      * malloc the memory, including the space for the header and fortification
  135.      * buffers
  136.      */  
  137. #ifdef WARN_ON_SIZE_T_OVERFLOW               
  138.     {
  139.         size_t private_size = sizeof(struct Header) 
  140.                             + FORTIFY_BEFORE_SIZE + size + FORTIFY_AFTER_SIZE;
  141.  
  142.         if(private_size < size) /* Check to see if the added baggage is larger than size_t */
  143.         {
  144.             sprintf(st_Buffer, 
  145.                     "\nFortify: %s.%ld\n         malloc(%ld) has overflowed size_t.\n",
  146.                     file, line, (unsigned long)size);
  147.             st_Output(st_Buffer);                      
  148.             FORTIFY_UNLOCK();
  149.             return(0);
  150.         }                              
  151.     }
  152. #endif                              
  153.  
  154.     ptr = malloc(sizeof(struct Header) + 
  155.                  FORTIFY_BEFORE_SIZE + size + FORTIFY_AFTER_SIZE);
  156.     if(!ptr)
  157.     {
  158. #ifdef WARN_ON_MALLOC_FAIL
  159.         sprintf(st_Buffer, "\nFortify: %s.%ld\n         malloc(%ld) failed\n",
  160.                 file, line, (unsigned long)size);
  161.         st_Output(st_Buffer);
  162. #endif
  163.  
  164.         FORTIFY_UNLOCK();
  165.         return(0);       
  166.     }
  167.  
  168.     /*
  169.      * Initialize and validate the header
  170.      */
  171.     h = (struct Header *)ptr;
  172.  
  173.     h->Size = size;
  174.   
  175.     h->File = file;
  176.     h->Line = line;  
  177.  
  178.     h->Next = st_Head;
  179.     h->Prev = 0;
  180.     
  181.     h->Scope = st_Scope;
  182.  
  183.     if(st_Head)
  184.     {
  185.         st_Head->Prev = h;
  186.         MakeHeaderValid(st_Head);  
  187.     }
  188.  
  189.     st_Head = h;
  190.   
  191.     MakeHeaderValid(h);
  192.  
  193.  
  194.     /*
  195.      * Initialize the fortifications
  196.      */    
  197.     SetFortification(ptr + sizeof(struct Header),
  198.                      FORTIFY_BEFORE_VALUE, FORTIFY_BEFORE_SIZE);
  199.     SetFortification(ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE + size,
  200.                      FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  201.  
  202. #ifdef FILL_ON_MALLOC 
  203.     /*
  204.      * Fill the actual user memory
  205.      */  
  206.     SetFortification(ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE,
  207.                      FILL_ON_MALLOC_VALUE, size);
  208. #endif
  209.  
  210.     /*
  211.      * We return the address of the user's memory, not the start of the block,
  212.      * which points to our magic cookies
  213.      */
  214.  
  215.     FORTIFY_UNLOCK();
  216.  
  217.     return(ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE);
  218. }
  219.  
  220. /* 
  221.  * Fortify_free() - This free must be used for all memory allocated with
  222.  *                  Fortify_malloc().
  223.  *
  224.  *   Features:
  225.  *     + Pointers are validated before attempting a free - the pointer
  226.  *       must point to a valid malloc'd bit of memory.
  227.  *     + Detects attempts at freeing the same block of memory twice
  228.  *     + Can clear out memory as it is free'd, to prevent code from using
  229.  *       the memory after it's been freed.
  230.  *     + Checks the sentinals of the memory being freed.
  231.  *     + Can check the sentinals of all memory.
  232.  */
  233.  
  234. void FORTIFY_STORAGE
  235. Fortify_free(void *uptr, char *file, unsigned long line)
  236. {
  237.     unsigned char *ptr = (unsigned char *)uptr - sizeof(struct Header) - FORTIFY_BEFORE_SIZE;
  238.     struct Header *h = (struct Header *)ptr;
  239.  
  240.     FORTIFY_LOCK();
  241.   
  242.     if(st_Disabled)
  243.     {
  244.         free(uptr);
  245.         FORTIFY_UNLOCK();
  246.         return;
  247.     }
  248.  
  249. #ifdef CHECK_ALL_MEMORY_ON_FREE
  250.     Fortify_CheckAllMemory(file, line);
  251. #endif  
  252.  
  253. #ifdef PARANOID_FREE
  254.     if(!IsOnList(h))
  255.     {
  256.         sprintf(st_Buffer, 
  257.          "\nFortify: %s.%ld\n         Invalid pointer, corrupted header, or possible free twice\n",
  258.                 file, line);
  259.         st_Output(st_Buffer);
  260.         OutputLastVerifiedPoint();
  261.         goto fail;
  262.     }
  263. #endif
  264.  
  265.     if(!CheckBlock(h, file, line))
  266.         goto fail;
  267.     
  268.     /*
  269.      * Remove the block from the list
  270.      */
  271.     if(h->Prev)
  272.     {
  273.         if(!CheckBlock(h->Prev, file, line))
  274.             goto fail;
  275.       
  276.         h->Prev->Next = h->Next;
  277.         MakeHeaderValid(h->Prev);
  278.     }
  279.     else
  280.         st_Head = h->Next;
  281.   
  282.     if(h->Next)
  283.     {
  284.         if(!CheckBlock(h->Next, file, line))
  285.             goto fail;
  286.  
  287.         h->Next->Prev = h->Prev;
  288.         MakeHeaderValid(h->Next);    
  289.     }    
  290.  
  291. #ifdef FILL_ON_FREE
  292.     /*
  293.      * Nuke out all memory that is about to be freed
  294.      */
  295.     SetFortification(ptr, FILL_ON_FREE_VALUE, 
  296.                      sizeof(struct Header) + FORTIFY_BEFORE_SIZE + h->Size + FORTIFY_AFTER_SIZE);
  297. #endif               
  298.  
  299.     /*
  300.      * And do the actual free
  301.      */
  302.     free(ptr);
  303.     FORTIFY_UNLOCK();
  304.     return;
  305.  
  306. fail:
  307.     sprintf(st_Buffer, "         free(%p) failed\n", uptr);
  308.     st_Output(st_Buffer);  
  309.     FORTIFY_UNLOCK();
  310. }
  311.  
  312. /*
  313.  * Fortify_realloc() - Uses Fortify_malloc() and Fortify_free() to implement
  314.  *                     realloc().
  315.  *
  316.  *   Features: 
  317.  *        + The realloc'd block is ALWAYS moved.
  318.  *        + The pointer passed to realloc() is verified in the same way that 
  319.  *          Fortify_free() verifies pointers before it frees them.
  320.  *        + All the Fortify_malloc() and Fortify_free() protection
  321.  */
  322. void *FORTIFY_STORAGE
  323. Fortify_realloc(void *ptr, size_t new_size, char *file, unsigned long line)
  324. {
  325.     void *new_ptr;
  326.     struct Header *h = (struct Header *)
  327.                        ((unsigned char *)ptr - sizeof(struct Header) - FORTIFY_BEFORE_SIZE);
  328.  
  329.     if(st_Disabled)
  330.     {
  331.         FORTIFY_LOCK();
  332.         new_ptr = realloc(ptr, new_size);
  333.         FORTIFY_UNLOCK();
  334.         return(new_ptr);
  335.     }
  336.  
  337.     if(!ptr)
  338.         return(Fortify_malloc(new_size, file, line));
  339.     
  340.     FORTIFY_LOCK();
  341.  
  342.     if(!IsOnList(h))
  343.     {
  344.         sprintf(st_Buffer, 
  345.                 "\nFortify: %s.%ld\n         Invalid pointer or corrupted header passed to realloc\n",
  346.                 file, line);
  347.         st_Output(st_Buffer);
  348.         goto fail;
  349.     }
  350.  
  351.     if(!CheckBlock(h, file, line))
  352.         goto fail;
  353.   
  354.     new_ptr = Fortify_malloc(new_size, file, line);
  355.     if(!new_ptr)
  356.     {
  357.         FORTIFY_UNLOCK();
  358.         return(0);
  359.     }
  360.   
  361.     if(h->Size < new_size) 
  362.         memcpy(new_ptr, ptr, h->Size);
  363.     else
  364.         memcpy(new_ptr, ptr, new_size);
  365.  
  366.     Fortify_free(ptr, file, line);
  367.     FORTIFY_UNLOCK();
  368.     return(new_ptr);
  369.   
  370. fail:
  371.     sprintf(st_Buffer, "         realloc(%p, %ld) failed\n", ptr, (unsigned long)new_size);
  372.     st_Output(st_Buffer);  
  373.     FORTIFY_UNLOCK();
  374.     return (NULL);
  375. }     
  376.  
  377. /*
  378.  * Fortifty_calloc() - Uses Fortify_malloc() to implement calloc(). Much
  379.  *                     the same protection as Fortify_malloc().
  380.  */
  381. void *FORTIFY_STORAGE
  382. Fortify_calloc(size_t num, size_t size, char *file, unsigned long line)
  383. {
  384.     void *ptr;
  385.  
  386.     ptr = Fortify_malloc(num * size, file, line);
  387.   
  388.     if(ptr)
  389.         memset(ptr, 0, num * size);
  390.  
  391.     return(ptr);
  392. }
  393.  
  394. /*
  395.  * Fortify_CheckPointer() - Returns true if the uptr points to a valid
  396.  *   piece of Fortify_malloc()'d memory. The memory must be on the malloc'd
  397.  *   list, and it's sentinals must be in tact.
  398.  *     If anything is wrong, an error message is issued.
  399.  *
  400.  *   (Note - if fortify is disabled, this function always returns true).
  401.  */
  402. int FORTIFY_STORAGE
  403. Fortify_CheckPointer(void *uptr, char *file, unsigned long line)
  404. {
  405.     unsigned char *ptr = (unsigned char *)uptr - sizeof(struct Header) - FORTIFY_BEFORE_SIZE;
  406.     int r;
  407.   
  408.     if(st_Disabled)
  409.         return(1);
  410.  
  411.     FORTIFY_LOCK();
  412.  
  413.     if(!IsOnList((struct Header *)ptr))
  414.     {
  415.         sprintf(st_Buffer, 
  416.                "\nFortify: %s.%ld\n         Invalid pointer or corrupted header detected (%p)\n",
  417.                file, line, uptr);
  418.         st_Output(st_Buffer);
  419.         FORTIFY_UNLOCK();
  420.         return(0);
  421.     }
  422.  
  423.     r = CheckBlock((struct Header *)ptr, file, line);
  424.     FORTIFY_UNLOCK();
  425.     return r;
  426. }
  427.  
  428. /*
  429.  * Fortify_SetOutputFunc(OutputFuncPtr Output) - Sets the function used to
  430.  *   output all error and diagnostic messages by fortify. The output function 
  431.  *   takes a single unsigned char * argument, and must be able to handle newlines.
  432.  *     The function returns the old pointer.
  433.  */
  434. Fortify_OutputFuncPtr FORTIFY_STORAGE
  435. Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output)
  436. {
  437.     OutputFuncPtr Old = st_Output;
  438.  
  439.     st_Output = Output;
  440.   
  441.     return(Old);
  442. }
  443.  
  444. /*
  445.  * Fortify_SetMallocFailRate(int Percent) - Fortify_malloc() will make the
  446.  *   malloc attempt fail this Percent of the time, even if the memory is
  447.  *   available. Useful to "stress-test" an application. Returns the old
  448.  *   value. The fail rate defaults to 0.
  449.  */
  450. int FORTIFY_STORAGE
  451. Fortify_SetMallocFailRate(int Percent)
  452. {
  453.     int Old = st_MallocFailRate;
  454.   
  455.     st_MallocFailRate = Percent;
  456.   
  457.     return(Old);
  458. }
  459.  
  460.  
  461. /*
  462.  * Fortify_CheckAllMemory() - Checks the sentinals of all malloc'd memory.
  463.  *   Returns the number of blocks that failed. 
  464.  *
  465.  *  (If Fortify is disabled, this function always returns 0).
  466.  */
  467. int FORTIFY_STORAGE
  468. Fortify_CheckAllMemory(char *file, unsigned long line)
  469. {
  470.     struct Header *curr = st_Head;
  471.     int count = 0;
  472.  
  473.     if(st_Disabled)
  474.         return(0);
  475.  
  476.     FORTIFY_LOCK();
  477.  
  478.     while(curr)
  479.     {
  480.         if(!CheckBlock(curr, file, line))
  481.             count++;
  482.  
  483.         curr = curr->Next;      
  484.     }
  485.   
  486.     if(file)
  487.     {
  488.         st_LastVerifiedFile = file;
  489.         st_LastVerifiedLine = line;
  490.     }
  491.  
  492.     FORTIFY_UNLOCK();
  493.     return(count);
  494. }
  495.  
  496. /* Fortify_EnterScope - enters a new Fortify scope level. 
  497.  * returns the new scope level.
  498.  */
  499. int FORTIFY_STORAGE
  500. Fortify_EnterScope(char *file, unsigned long line)
  501. {
  502.     return(++st_Scope);
  503. }
  504.  
  505. /* Fortify_LeaveScope - leaves a Fortify scope level,
  506.  * also prints a memory dump of all non-freed memory that was allocated
  507.  * during the scope being exited.
  508.  */
  509. int FORTIFY_STORAGE
  510. Fortify_LeaveScope(char *file, unsigned long line)
  511. {
  512.     struct Header *curr = st_Head;
  513.     int count = 0;
  514.     unsigned long size = 0;
  515.  
  516.     if(st_Disabled)
  517.         return(0);
  518.  
  519.     FORTIFY_LOCK();
  520.  
  521.     st_Scope--;
  522.     while(curr)
  523.     {
  524.         if(curr->Scope > st_Scope)
  525.         {
  526.             if(count == 0)
  527.             {
  528.                 sprintf(st_Buffer, "\nFortify: Memory Dump at %s.%ld\n", file, line);
  529.                 st_Output(st_Buffer);
  530.                 OutputLastVerifiedPoint();
  531.                 sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  532.                 st_Output(st_Buffer);
  533.             }
  534.             
  535.             OutputHeader(curr);
  536.             count++;
  537.             size += curr->Size;
  538.         }
  539.  
  540.         curr = curr->Next;      
  541.     }
  542.  
  543.     if(count)
  544.     {
  545.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and",
  546.                         (unsigned long)(count * (sizeof(struct Header) + FORTIFY_BEFORE_SIZE + FORTIFY_AFTER_SIZE)));
  547.                         st_Output(st_Buffer);
  548.  
  549.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);
  550.         st_Output(st_Buffer);
  551.     }
  552.  
  553.     FORTIFY_UNLOCK();
  554.     return(count);
  555. }
  556.  
  557. /*
  558.  * Fortify_OutputAllMemory() - Outputs the entire list of currently
  559.  *     malloc'd memory. For each malloc'd block is output it's Address,
  560.  *   Size, and the SourceFile and Line that allocated it.
  561.  *
  562.  *   If there is no memory on the list, this function outputs nothing.
  563.  *
  564.  *   It returns the number of blocks on the list, unless fortify has been
  565.  *   disabled, in which case it always returns 0.
  566.  */
  567. int FORTIFY_STORAGE
  568. Fortify_OutputAllMemory(char *file, unsigned long line)
  569. {
  570.     struct Header *curr = st_Head;
  571.     int count = 0;
  572.     unsigned long size = 0;
  573.  
  574.     if(st_Disabled)
  575.         return(0);
  576.  
  577.     FORTIFY_LOCK();
  578.  
  579.     if(curr)
  580.     {
  581.         sprintf(st_Buffer, "\nFortify: Memory Dump at %s.%ld\n", file, line);
  582.         st_Output(st_Buffer);
  583.         OutputLastVerifiedPoint();
  584.         sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  585.         st_Output(st_Buffer);
  586.                                 
  587.         while(curr)
  588.         {
  589.             OutputHeader(curr);
  590.             count++;
  591.             size += curr->Size;
  592.             curr = curr->Next;      
  593.         }
  594.                      
  595.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and", 
  596.                 (unsigned long)(count * (sizeof(struct Header) + FORTIFY_BEFORE_SIZE + FORTIFY_AFTER_SIZE)));
  597.         st_Output(st_Buffer);
  598.  
  599.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);  
  600.         st_Output(st_Buffer);
  601.     }
  602.   
  603.     FORTIFY_UNLOCK();
  604.     return(count);
  605. }
  606.  
  607. /* Fortify_DumpAllMemory(Scope) - Outputs the entire list of currently
  608.  * new'd memory within the specified scope. For each new'd block is output
  609.  * it's Address, Size, the SourceFile and Line that allocated it, a hex dump
  610.  * of the contents of the memory and an ascii dump of printable characters.
  611.  *
  612.  * If there is no memory on the list, this function outputs nothing.
  613.  *
  614.  * It returns the number of blocks on the list, unless Fortify has been
  615.  * disabled, in which case it always returns 0.
  616.  */
  617. int FORTIFY_STORAGE
  618. Fortify_DumpAllMemory(int scope, char *file, unsigned long line)
  619. {
  620.     struct Header *curr = st_Head;
  621.     int count = 0;
  622.     unsigned long size = 0;
  623.  
  624.     if(st_Disabled)
  625.         return(0);
  626.  
  627.     FORTIFY_LOCK();
  628.  
  629.     while(curr)
  630.     {
  631.         if(curr->Scope >= scope)
  632.         {
  633.             if(count == 0)
  634.             {
  635.                 sprintf(st_Buffer, "\nFortify: Memory Dump at %s.%ld\n", file, line);
  636.                 st_Output(st_Buffer);
  637.                 OutputLastVerifiedPoint();
  638.                 sprintf(st_Buffer, "%11s %8s %s\n", "Address", "Size", "Allocator");
  639.                 st_Output(st_Buffer);
  640.             }
  641.  
  642.             OutputHeader(curr);
  643.             OutputMemory(curr);
  644.             st_Output("\n");
  645.             count++;
  646.             size += curr->Size;
  647.         }
  648.  
  649.         curr = curr->Next;
  650.     }
  651.  
  652.     if(count)
  653.     {
  654.         sprintf(st_Buffer, "%11s %8ld bytes overhead\n", "and",
  655.                         (unsigned long)(count * (sizeof(struct Header) + FORTIFY_BEFORE_SIZE + FORTIFY_AFTER_SIZE)));
  656.                         st_Output(st_Buffer);
  657.  
  658.         sprintf(st_Buffer,"%11s %8ld bytes in %d blocks\n", "total", size, count);
  659.         st_Output(st_Buffer);
  660.     }
  661.  
  662.     FORTIFY_UNLOCK();
  663.     return(count);
  664. }
  665.  
  666. /*
  667.  * Fortify_Disable() - This function provides a mechanism to disable Fortify
  668.  *   without recompiling all the sourcecode. It can only be called, though,
  669.  *   when there is no memory on the Fortify malloc'd list. (Ideally, at the 
  670.  *   start of the program before any memory has been allocated). If you
  671.  *   call this function when there IS memory on the Fortify malloc'd list,
  672.  *   it will issue an error, and fortify will not be disabled.
  673.  */
  674. int FORTIFY_STORAGE
  675. Fortify_Disable(char *file, unsigned long line)
  676. {
  677.     int result;
  678.     FORTIFY_LOCK();
  679.  
  680.     if(st_Head)
  681.     {
  682.         sprintf(st_Buffer, "Fortify: %s.%d\n", file, line);
  683.         st_Output(st_Buffer);
  684.         st_Output("         Fortify_Disable failed\n");
  685.         st_Output("         (because there is memory on the Fortify memory list)\n");
  686.     
  687.         Fortify_OutputAllMemory(file, line);
  688.         result = 0;            
  689.     }
  690.     else
  691.     {
  692.         st_Disabled = 1;
  693.         result = 1;
  694.     }
  695.   
  696.     FORTIFY_UNLOCK();
  697.     return(result);
  698. }
  699.  
  700. /* 
  701.  * Check a block's header and fortifications.
  702.  */
  703. static int CheckBlock(struct Header *h, char *file, unsigned long line)
  704. {   
  705.     unsigned char *ptr = (unsigned char *)h;
  706.     int result = 1;
  707.  
  708.     if(!IsHeaderValid(h))
  709.     {
  710.         sprintf(st_Buffer, 
  711.                 "\nFortify: %s.%ld\n         Invalid pointer or corrupted header detected (%p)\n",
  712.                 file, line, ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE);
  713.         st_Output(st_Buffer);
  714.         OutputLastVerifiedPoint();
  715.         return(0);
  716.     }
  717.  
  718.     if(!CheckFortification(ptr + sizeof(struct Header),
  719.                            FORTIFY_BEFORE_VALUE, FORTIFY_BEFORE_SIZE))
  720.     {
  721.         sprintf(st_Buffer,
  722.                 "\nFortify: %s.%ld\n         Memory overrun detected before block\n",
  723.                 file, line);
  724.         st_Output(st_Buffer);
  725.  
  726.         sprintf(st_Buffer,"         (%p,%ld,%s.%ld)\n",
  727.                 ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE,
  728.                (unsigned long)h->Size, h->File, h->Line);
  729.         st_Output(st_Buffer);
  730.     
  731.         OutputFortification(ptr + sizeof(struct Header),
  732.                             FORTIFY_BEFORE_VALUE, FORTIFY_BEFORE_SIZE);
  733.         OutputLastVerifiedPoint();
  734.         result = 0;                        
  735.     }
  736.                            
  737.     if(!CheckFortification(ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE + h->Size,
  738.                            FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE))
  739.     {
  740.         sprintf(st_Buffer, "\nFortify: %s.%ld\n         Memory overrun detected after block\n",
  741.                            file, line);
  742.         st_Output(st_Buffer);
  743.  
  744.         sprintf(st_Buffer,"         (%p,%ld,%s.%ld)\n",
  745.                           ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE,
  746.                          (unsigned long)h->Size, h->File, h->Line);
  747.         st_Output(st_Buffer);
  748.  
  749.         OutputFortification(ptr + sizeof(struct Header) + FORTIFY_BEFORE_SIZE + h->Size,
  750.                             FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  751.         OutputLastVerifiedPoint();
  752.         result = 0;
  753.     }
  754.  
  755.     return(result);    
  756. }
  757.  
  758. /*
  759.  * Checks if the _size_ bytes from _ptr_ are all set to _value_
  760.  */
  761. static int CheckFortification(unsigned char *ptr, unsigned char value, size_t size)
  762. {
  763.     while(size--)
  764.         if(*ptr++ != value)
  765.             return(0);
  766.       
  767.     return(1);      
  768. }
  769.  
  770. /*
  771.  * Set the _size_ bytes from _ptr_ to _value_.
  772.  */
  773. static void SetFortification(unsigned char *ptr, unsigned char value, size_t size)
  774. {
  775.     memset(ptr, value, size);
  776. }
  777.  
  778. /*
  779.  * Output the corrupted section of the fortification 
  780.  */
  781. // Output the corrupted section of the fortification
  782. static void
  783. OutputFortification(unsigned char *ptr, unsigned char value, size_t size)
  784. {
  785.     unsigned long offset, column;
  786.     char    ascii[17];
  787.  
  788.     st_Output("Address     Offset Data");
  789.  
  790.     offset = 0;
  791.     column = 0;
  792.  
  793.     while(offset < size)
  794.     {
  795.         if(column == 0)
  796.         {
  797.             sprintf(st_Buffer, "\n%8p %8d ", ptr, offset);
  798.             st_Output(st_Buffer);
  799.         }
  800.  
  801.         sprintf(st_Buffer, "%02x ", *ptr);
  802.         st_Output(st_Buffer);
  803.  
  804.         ascii[ column ] = isprint( *ptr ) ? (char)(*ptr) : (char)(' ');
  805.         ascii[ column + 1 ] = '\0';
  806.  
  807.         ptr++;
  808.         offset++;
  809.         column++;
  810.  
  811.         if(column == 16)
  812.         {
  813.             st_Output( "   \"" );
  814.             st_Output( ascii );
  815.             st_Output( "\"" );
  816.             column = 0;
  817.         }
  818.     }
  819.  
  820.     if ( column != 0 )
  821.     {
  822.         while ( column ++ < 16 )
  823.         {
  824.             st_Output( "   " );
  825.         }
  826.         st_Output( "   \"" );
  827.         st_Output( ascii );
  828.         st_Output( "\"" );
  829.     }
  830.  
  831.     st_Output("\n");
  832. }
  833.  
  834. /*
  835.  * Returns true if the supplied pointer does indeed point to a real Header
  836.  */
  837. static int IsHeaderValid(struct Header *h)                                
  838. {
  839.     return(!ChecksumHeader(h));
  840. }
  841.  
  842. /*
  843.  * Updates the checksum to make the header valid
  844.  */
  845. static void MakeHeaderValid(struct Header *h)
  846. {
  847.     h->Checksum = 0;
  848.     h->Checksum = -ChecksumHeader(h);
  849. }
  850.  
  851. /*
  852.  * Calculate (and return) the checksum of the header. (Including the Checksum
  853.  * variable itself. If all is well, the checksum returned by this function should
  854.  * be 0.
  855.  */
  856. static int ChecksumHeader(struct Header *h)
  857. {
  858.     int c, checksum, *p;
  859.   
  860.     for(c = 0, checksum = 0, p = (int *)h; c < sizeof(struct Header)/sizeof(int); c++)
  861.         checksum += *p++;  
  862.     
  863.     return(checksum);
  864. }                  
  865.  
  866. /* 
  867.  * Examines the malloc'd list to see if the given header is on it.
  868.  */  
  869. static int IsOnList(struct Header *h)
  870. {
  871.     struct Header *curr;
  872.   
  873.     curr = st_Head;
  874.     while(curr)
  875.     {
  876.         if(curr == h)
  877.             return(1);
  878.       
  879.         curr = curr->Next;
  880.     }
  881.   
  882.     return(0);
  883. }
  884.  
  885. /*
  886.  * Hex and ascii dump the memory
  887.  */
  888. static void
  889. OutputMemory(struct Header *h)
  890. {
  891.     OutputFortification((unsigned char*)h + sizeof(struct Header) + FORTIFY_BEFORE_SIZE,
  892.                         0, h->Size);
  893. }
  894.  
  895.  
  896. /*
  897.  * Output the header...
  898.  */
  899. static void OutputHeader(struct Header *h)
  900. {
  901.     sprintf(st_Buffer, "%11p %8ld %s.%ld (%d)\n", 
  902.                        (unsigned char*)h + sizeof(struct Header) + FORTIFY_BEFORE_SIZE,
  903.                        (unsigned long)h->Size,
  904.                        h->File, h->Line, h->Scope);
  905.     st_Output(st_Buffer);
  906. }
  907.  
  908. static void OutputLastVerifiedPoint()
  909. {
  910.     sprintf(st_Buffer, "\nLast Verified point: %s.%ld\n", 
  911.                        st_LastVerifiedFile,
  912.                        st_LastVerifiedLine);
  913.     st_Output(st_Buffer);
  914. }
  915.  
  916.  
  917. #endif /* FORTIFY */
  918.